// Range v3 library
//
//  Copyright Eric Niebler 2014
//
//  Use, modification and distribution is subject to the
//  Boost Software License, Version 1.0. (See accompanying
//  file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//
// Project home: https://github.com/ericniebler/range-v3
//
//  Copyright 2005 - 2007 Adobe Systems Incorporated
//  Distributed under the MIT License(see accompanying file LICENSE_1_0_0.txt
//  or a copy at http://stlab.adobe.com/licenses.html)

//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include <nanorange/algorithm/is_partitioned.hpp>
#include <memory>
#include <utility>
#include "../catch.hpp"
#include "../test_utils.hpp"
#include "../test_iterators.hpp"

namespace stl2 = nano;

namespace {

struct is_odd {
	bool operator()(const int& i) const { return i & 1; }
};

template <class Iter, class Sent = Iter>
void
test_iter()
{
	{
		const int ia[] = {1, 2, 3, 4, 5, 6};
		CHECK(!stl2::is_partitioned(Iter(stl2::begin(ia)),
									Sent(stl2::end(ia)),
									is_odd()));
	}
	{
		const int ia[] = {1, 3, 5, 2, 4, 6};
		CHECK(stl2::is_partitioned(Iter(stl2::begin(ia)),
								   Sent(stl2::end(ia)),
								   is_odd()));
	}
	{
		const int ia[] = {2, 4, 6, 1, 3, 5};
		CHECK(!stl2::is_partitioned(Iter(stl2::begin(ia)),
									Sent(stl2::end(ia)),
									is_odd()));
	}
	{
		const int ia[] = {1, 3, 5, 2, 4, 6, 7};
		CHECK(!stl2::is_partitioned(Iter(stl2::begin(ia)),
									Sent(stl2::end(ia)),
									is_odd()));
	}
	{
		const int ia[] = {1, 3, 5, 2, 4, 6, 7};
		CHECK(stl2::is_partitioned(Iter(stl2::begin(ia)),
								   Sent(stl2::begin(ia)),
								   is_odd()));
	}
}

template <class Iter, class Sent = Iter>
void
test_range()
{
	{
		const int ia[] = {1, 2, 3, 4, 5, 6};
		CHECK(!stl2::is_partitioned(stl2::subrange(Iter(stl2::begin(ia)),
														  Sent(stl2::end(ia))),
									is_odd()));
	}
	{
		const int ia[] = {1, 3, 5, 2, 4, 6};
		CHECK(stl2::is_partitioned(stl2::subrange(Iter(stl2::begin(ia)),
														 Sent(stl2::end(ia))),
								   is_odd()));
	}
	{
		const int ia[] = {2, 4, 6, 1, 3, 5};
		CHECK(!stl2::is_partitioned(stl2::subrange(Iter(stl2::begin(ia)),
														  Sent(stl2::end(ia))),
									is_odd()));
	}
	{
		const int ia[] = {1, 3, 5, 2, 4, 6, 7};
		CHECK(!stl2::is_partitioned(stl2::subrange(Iter(stl2::begin(ia)),
														  Sent(stl2::end(ia))),
									is_odd()));
	}
	{
		const int ia[] = {1, 3, 5, 2, 4, 6, 7};
		CHECK(stl2::is_partitioned(stl2::subrange(Iter(stl2::begin(ia)),
														 Sent(stl2::begin(ia))),
								   is_odd()));
	}
}

struct S {
	int i;
};

}

TEST_CASE("alg.is_partitioned")
{
	test_iter<input_iterator<const int*> >();
	test_iter<input_iterator<const int*>, sentinel<const int*>>();

	test_range<input_iterator<const int*> >();
	test_range<input_iterator<const int*>, sentinel<const int*>>();

	// Test projections
	const S ia[] = {S{1}, S{3}, S{5}, S{2}, S{4}, S{6}};
	CHECK( stl2::is_partitioned(ia, is_odd(), &S::i) );
}
